﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NetAssist.Collections;
//using System.Collections;

namespace NetAssistTests
{
  [TestClass()]
  public class MapTests
  {
    [TestMethod()]
    public void MapConstructorTest()
    {
      Map<int, Pet> map1 = new Map<int, Pet>();
      map1.Add(1, new Pet { Name = "Daisy", Type = "Dog" });
      map1.Add(2, new Pet { Name = "Peanut", Type = "Cat" });
      map1.Add(3, new Pet { Name = "Sticker", Type = "Cat" });
      Assert.IsTrue(map1.Count == 3);

      Map<int, Pet> map2 = new Map<int, Pet>(map1);
      Assert.IsTrue(map2.Count == 3);
      Assert.IsTrue(map1[1].Name == map2[1].Name);
      Assert.IsTrue(map1[2].Name == map2[2].Name);
      Assert.IsTrue(map1[3].Name == map2[3].Name);

      Map<int, Pet> map3 = new Map<int, Pet>(null, new petComparer());
      try
      {
        map3.Add(1, new Pet { Name = "Daisy", Type = "Dog" });
        map3.Add(2, new Pet { Name = "Peanut", Type = "Cat" });
        map3.Add(3, new Pet { Name = "Sticker", Type = "Cat" });
      }
      catch { }
      Assert.IsTrue(map3.Count == 2);  //only one cat allowed by the comparer.

      try
      {
        Map<int, Pet> map4 = new Map<int, Pet>(map1, null, new petComparer());
      }
      catch { }
      Assert.IsTrue(map3.Count == 2);

      Assert.IsTrue(map3.KeyComparer.GetType().Name == "GenericEqualityComparer`1");
      Assert.IsTrue(map3.ValueComparer.GetType() == typeof(petComparer));
    }

    [TestMethod()]
    public void MapContainsTest()
    {
      Map<int, string> map1 = new Map<int, string>();
      map1.Add(1, "A");
      map1.Add(2, "B");
      map1.Add(new KeyValuePair<int, string>(3, "C"));
      map1.Add(new KeyValuePair<int, string>(4, "D"));
      map1.Add(new KeyValuePair<string, int>("E", 5));
      map1.Add(new KeyValuePair<string, int>("F", 6));

      Assert.IsTrue(map1.ContainsKey(2));
      Assert.IsTrue(map1.ContainsValue("D"));
      Assert.IsTrue(map1.ContainsKey(6));
      Assert.IsTrue(map1.ContainsValue("F"));
      Assert.IsTrue(map1.Contains(new KeyValuePair<int, string>(3, "C")));
      Assert.IsTrue(map1.Contains(new KeyValuePair<int, string>(5, "E")));
      Assert.IsTrue(map1.Contains(new KeyValuePair<string, int>("C", 3)));
      Assert.IsTrue(map1.Contains(new KeyValuePair<string, int>("E", 5)));
      Assert.IsTrue(!map1.Contains(new KeyValuePair<int, string>(3, "D")));
      Assert.IsTrue(!map1.Contains(new KeyValuePair<int, string>(4, "C")));

      int[] keys = new int[] { 1, 2, 3, 4, 5, 6 };
      string[] values = new string[] { "A", "B", "C", "D", "E", "F" };

      Assert.IsTrue(map1.Keys.SequenceEqual(keys));
      Assert.IsTrue(map1.Values.SequenceEqual(values));
    }

    [TestMethod()]
    public void MapGetSetRemoveTest()
    {
      Map<int, string> map1 = new Map<int, string>();
      map1.Add(1, "A");
      map1.Add(2, "B");
      map1.Add(new KeyValuePair<int, string>(3, "C"));
      map1.Add(new KeyValuePair<int, string>(4, "D"));
      map1.Add(new KeyValuePair<string, int>("E", 5));
      map1.Add(new KeyValuePair<string, int>("F", 6));


      map1[1] = "AAAA";
      map1["C"] = 3333;

      map1.Remove(2);
      map1.Remove(4);
      map1.Remove(new KeyValuePair<int, string>(5, "E"));
      map1.Remove(new KeyValuePair<string, int>("F", 6));

      if (map1.Remove(-2))
      { Assert.Fail(); }

      if (map1.Remove("ZZZ"))
      { Assert.Fail(); }

      int[] keys = new int[] { 1, 3333 };
      string[] values = new string[] { "AAAA", "C" };

      Assert.IsTrue(map1.Keys.SequenceEqual(keys));
      Assert.IsTrue(map1.Values.SequenceEqual(values));

      Assert.IsTrue(map1[1] == "AAAA");
      Assert.IsTrue(map1["C"] == 3333);

      map1[1] = "AAAA";
      map1["C"] = 3333;

      string v;
      int k;
      if (map1.TryGetKey("AAAA", out k))
      { Assert.IsTrue(k == 1); }
      if (map1.TryGetValue(3333, out v))
      { Assert.IsTrue(v == "C"); }
      if (map1.TryGetKey("*AAAA", out k))
      { Assert.Fail(); }
      if (map1.TryGetValue(-3333, out v))
      { Assert.Fail(); }

      int idx = 0;
      foreach (var item in (IEnumerable)map1)
      {
        switch (idx)
        {
          case 0:
            Assert.IsTrue(((KeyValuePair<int, string>)item).Key == 1);
            break;
          case 1:
            Assert.IsTrue((int)(((KeyValuePair<int, string>)item).Key) == 3333);
            break;
          default:
            Assert.Fail();
            break;
        }
        idx++;
      }

      KeyValuePair<int, string>[] arr = new KeyValuePair<int, string>[5];
      map1.CopyTo(arr, 2);
      Assert.IsTrue(map1[1] == arr[2].Value);
      Assert.IsTrue(map1["C"] == arr[3].Key);


      map1.Clear();
      Assert.IsTrue(map1.Count == 0);

      Assert.IsTrue(map1.IsReadOnly == false);
    }
  }

  public class Pet
  {
    public string Name { get; set; }
    public string Type { get; set; }
  }

  public class petComparer : IEqualityComparer<Pet>
  {
    #region IEqualityComparer<Pet> Members

    public bool Equals(Pet x, Pet y)
    {
      return x.Type == y.Type;
    }

    public int GetHashCode(Pet obj)
    {
      return obj.Type.GetHashCode();
    }

    #endregion
  }
}
